<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>BMC实验管理平台 - 工作流管理</title>
    <!-- Element Plus CSS -->
    <link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css">
    <!-- Element Plus Icons -->
    <link rel="stylesheet" href="https://unpkg.com/@element-plus/icons-vue">
    <!-- Vue 3 -->
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <!-- Element Plus -->
    <script src="https://unpkg.com/element-plus"></script>
    <!-- Element Plus Icons -->
    <script src="https://unpkg.com/@element-plus/icons-vue"></script>
    <!-- Axios -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <style>
        body {
            margin: 0;
            font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
        }
        #app {
            height: 100vh;
            display: flex;
            flex-direction: column;
        }
        .header {
            background-color: #409EFF;
            color: white;
            padding: 20px;
            text-align: center;
        }
        .nav-tabs {
            background-color: #f5f7fa;
            padding: 10px 20px;
        }
        .main-container {
            flex: 1;
            padding: 20px;
            overflow: auto;
        }

        /* 工作流编辑器样式 */
        .workflow-editor {
            display: flex;
            height: calc(100vh - 200px);
            gap: 10px;
        }
        .node-palette {
            width: 200px;
            background: #f5f7fa;
            padding: 10px;
            border-radius: 4px;
            overflow-y: auto;
        }
        .node-item {
            background: white;
            border: 1px solid #dcdfe6;
            border-radius: 4px;
            padding: 10px;
            margin-bottom: 10px;
            cursor: move;
            user-select: none;
        }
        .node-item:hover {
            border-color: #409EFF;
            box-shadow: 0 2px 4px rgba(64, 158, 255, 0.2);
        }
        .canvas-container {
            flex: 1;
            background: white;
            border: 1px solid #dcdfe6;
            border-radius: 4px;
            position: relative;
            overflow: auto;
        }
        .workflow-canvas {
            position: relative;
            min-height: 100%;
            min-width: 100%;
        }
        .workflow-node {
            position: absolute;
            background: white;
            border: 2px solid #409EFF;
            border-radius: 8px;
            padding: 15px;
            min-width: 150px;
            cursor: move;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
        }
        .workflow-node.selected {
            border-color: #67C23A;
            box-shadow: 0 2px 12px rgba(103, 194, 58, 0.3);
        }
        .workflow-node .node-header {
            font-weight: bold;
            margin-bottom: 5px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .workflow-node .node-type {
            font-size: 12px;
            color: #909399;
        }
        .workflow-node .node-delete {
            color: #F56C6C;
            cursor: pointer;
            font-size: 16px;
        }
        .node-connector {
            position: absolute;
            width: 10px;
            height: 10px;
            background: #409EFF;
            border-radius: 50%;
            cursor: pointer;
        }
        .node-connector.input {
            left: -5px;
            top: 50%;
            transform: translateY(-50%);
        }
        .node-connector.output {
            right: -5px;
            top: 50%;
            transform: translateY(-50%);
        }
        .config-panel {
            width: 300px;
            background: #f5f7fa;
            padding: 10px;
            border-radius: 4px;
            overflow-y: auto;
        }

        /* SVG 连线样式 */
        .connections-svg {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 0;
        }
        .workflow-node {
            z-index: 1;
        }

        /* 节点类型图标颜色 */
        .node-icon.create-experiment { color: #409EFF; }
        .node-icon.download-data { color: #67C23A; }
        .node-icon.data-processing { color: #E6A23C; }
        .node-icon.condition { color: #F56C6C; }

        /* 工作流实例监控样式 */
        .status-badge {
            display: inline-block;
            padding: 2px 8px;
            border-radius: 3px;
            font-size: 12px;
        }
        .status-running { background: #E6F7FF; color: #1890FF; }
        .status-completed { background: #F6FFED; color: #52C41A; }
        .status-failed { background: #FFF1F0; color: #FF4D4F; }
        .status-paused { background: #FFF7E6; color: #FA8C16; }
    </style>
</head>
<body>
    <div id="app">
        <div class="header">
            <h1>BMC实验管理平台 - 工作流管理</h1>
        </div>

        <div class="nav-tabs">
            <el-radio-group v-model="activeTab" size="large">
                <el-radio-button label="list">工作流列表</el-radio-button>
                <el-radio-button label="editor">工作流编辑器</el-radio-button>
                <el-radio-button label="instances">工作流实例</el-radio-button>
            </el-radio-group>
        </div>

        <div class="main-container">
            <!-- 工作流列表 -->
            <div v-show="activeTab === 'list'">
                <el-row :gutter="20" style="margin-bottom: 20px;">
                    <el-col :span="6">
                        <el-button type="primary" @click="createNewWorkflow">创建工作流</el-button>
                    </el-col>
                    <el-col :span="18">
                        <el-input
                            v-model="searchName"
                            placeholder="搜索工作流名称"
                            clearable
                            @clear="fetchWorkflows"
                            @keyup.enter="fetchWorkflows"
                        >
                            <template #append>
                                <el-button @click="fetchWorkflows">搜索</el-button>
                            </template>
                        </el-input>
                    </el-col>
                </el-row>

                <el-table :data="workflows" v-loading="loading" stripe style="width: 100%">
                    <el-table-column prop="id" label="ID" width="80"></el-table-column>
                    <el-table-column prop="name" label="工作流名称" width="200"></el-table-column>
                    <el-table-column prop="description" label="描述"></el-table-column>
                    <el-table-column prop="status" label="状态" width="100"></el-table-column>
                    <el-table-column prop="created_at" label="创建时间" width="180">
                        <template #default="scope">
                            {{ formatDate(scope.row.created_at) }}
                        </template>
                    </el-table-column>
                    <el-table-column label="操作" width="300">
                        <template #default="scope">
                            <el-button size="small" @click="editWorkflow(scope.row)">编辑</el-button>
                            <el-button size="small" type="success" @click="runWorkflow(scope.row.id)">运行</el-button>
                            <el-button size="small" type="danger" @click="deleteWorkflow(scope.row.id)">删除</el-button>
                        </template>
                    </el-table-column>
                </el-table>

                <el-pagination
                    v-model:current-page="currentPage"
                    v-model:page-size="pageSize"
                    :page-sizes="[10, 20, 50]"
                    :total="total"
                    layout="total, sizes, prev, pager, next"
                    @size-change="fetchWorkflows"
                    @current-change="fetchWorkflows"
                    style="margin-top: 20px; justify-content: center"
                />
            </div>

            <!-- 工作流编辑器 -->
            <div v-show="activeTab === 'editor'" class="workflow-editor">
                <!-- 节点面板 -->
                <div class="node-palette">
                    <h3 style="margin-top: 0;">节点类型</h3>
                    <div
                        v-for="nodeType in nodeTypes"
                        :key="nodeType.type"
                        class="node-item"
                        @click="addNode(nodeType)"
                    >
                        <div style="display: flex; align-items: center; gap: 8px;">
                            <i :class="['node-icon', nodeType.type, nodeType.icon]" style="font-size: 20px;"></i>
                            <div>
                                <div style="font-weight: bold;">{{ nodeType.name }}</div>
                                <div style="font-size: 12px; color: #909399;">{{ nodeType.description }}</div>
                            </div>
                        </div>
                    </div>

                    <el-divider />

                    <el-button type="primary" @click="saveWorkflow" style="width: 100%;">保存工作流</el-button>
                    <el-button @click="clearCanvas" style="width: 100%; margin-top: 10px;">清空画布</el-button>
                </div>

                <!-- 画布区域 -->
                <div class="canvas-container">
                    <div class="workflow-canvas" ref="canvas" @click="deselectNode">
                        <!-- SVG 用于绘制连线 -->
                        <svg class="connections-svg" :width="canvasSize.width" :height="canvasSize.height">
                            <line
                                v-for="(conn, index) in connections"
                                :key="index"
                                :x1="conn.x1"
                                :y1="conn.y1"
                                :x2="conn.x2"
                                :y2="conn.y2"
                                stroke="#409EFF"
                                stroke-width="2"
                                marker-end="url(#arrowhead)"
                            />
                            <defs>
                                <marker id="arrowhead" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
                                    <polygon points="0 0, 10 3, 0 6" fill="#409EFF" />
                                </marker>
                            </defs>
                        </svg>

                        <!-- 工作流节点 -->
                        <div
                            v-for="node in editorNodes"
                            :key="node.id"
                            :ref="'node-' + node.id"
                            class="workflow-node"
                            :class="{ selected: selectedNode && selectedNode.id === node.id }"
                            :style="{ left: node.x + 'px', top: node.y + 'px' }"
                            @click.stop="selectNode(node)"
                            @mousedown="startDrag($event, node)"
                        >
                            <div class="node-header">
                                <span>{{ node.name }}</span>
                                <span class="node-delete" @click.stop="removeNode(node.id)">×</span>
                            </div>
                            <div class="node-type">{{ node.type }}</div>
                            <!-- 输入连接点 -->
                            <div class="node-connector input" v-if="node.type !== 'create_experiment'" @click.stop="connectInput(node)"></div>
                            <!-- 输出连接点 -->
                            <div class="node-connector output" @click.stop="connectOutput(node)"></div>
                        </div>
                    </div>
                </div>

                <!-- 配置面板 -->
                <div class="config-panel">
                    <h3 style="margin-top: 0;">配置面板</h3>
                    <div v-if="!selectedNode" style="color: #909399; text-align: center; margin-top: 50px;">
                        请选择一个节点进行配置
                    </div>
                    <div v-else>
                        <el-form label-width="80px" size="small">
                            <el-form-item label="节点ID">
                                <el-input v-model="selectedNode.id" disabled></el-input>
                            </el-form-item>
                            <el-form-item label="节点名称">
                                <el-input v-model="selectedNode.name"></el-input>
                            </el-form-item>
                            <el-form-item label="节点类型">
                                <el-input v-model="selectedNode.type" disabled></el-input>
                            </el-form-item>

                            <el-divider />

                            <!-- 创建实验节点配置 -->
                            <template v-if="selectedNode.type === 'create_experiment'">
                                <el-form-item label="实验模板">
                                    <el-select v-model="selectedNode.config.template_id" placeholder="选择模板">
                                        <el-option
                                            v-for="tmpl in experimentTemplates"
                                            :key="tmpl.id"
                                            :label="tmpl.name"
                                            :value="tmpl.id"
                                        />
                                    </el-select>
                                </el-form-item>
                                <el-form-item label="实验名称">
                                    <el-input v-model="selectedNode.config.experiment_name" placeholder="{{workflow.name}}-exp"></el-input>
                                </el-form-item>
                                <el-form-item label="轮询频率">
                                    <el-select v-model="selectedNode.config.poll_interval">
                                        <el-option label="30分钟" value="30min" />
                                        <el-option label="1小时" value="1h" />
                                        <el-option label="2小时" value="2h" />
                                        <el-option label="3小时" value="3h" />
                                        <el-option label="6小时" value="6h" />
                                    </el-select>
                                </el-form-item>
                            </template>

                            <!-- 下载数据节点配置 -->
                            <template v-if="selectedNode.type === 'download_data'">
                                <el-form-item label="数据源类型">
                                    <el-select v-model="selectedNode.config.source_type">
                                        <el-option label="OBS" value="OBS" />
                                        <el-option label="HTTP" value="HTTP" />
                                        <el-option label="FTP" value="FTP" />
                                    </el-select>
                                </el-form-item>
                                <el-form-item label="源路径">
                                    <el-input v-model="selectedNode.config.source_path"></el-input>
                                </el-form-item>
                                <el-form-item label="目标路径">
                                    <el-input v-model="selectedNode.config.target_path"></el-input>
                                </el-form-item>
                                <el-form-item label="下载策略">
                                    <el-select v-model="selectedNode.config.download_strategy">
                                        <el-option label="覆盖" value="overwrite" />
                                        <el-option label="跳过" value="skip" />
                                        <el-option label="增量" value="incremental" />
                                    </el-select>
                                </el-form-item>
                            </template>

                            <!-- 数据处理节点配置 -->
                            <template v-if="selectedNode.type === 'data_processing'">
                                <el-form-item label="API功能">
                                    <el-select v-model="selectedNode.config.api_function">
                                        <el-option label="数据集下载" value="dataset_download" />
                                        <el-option label="数据清洗" value="data_cleaning" />
                                        <el-option label="数据转换" value="data_transform" />
                                    </el-select>
                                </el-form-item>
                                <el-form-item label="请求参数">
                                    <el-input v-model="selectedNode.config.request_params" type="textarea" rows="3" placeholder='{"key": "value"}'></el-input>
                                </el-form-item>
                            </template>

                            <!-- 条件分支节点配置 -->
                            <template v-if="selectedNode.type === 'condition'">
                                <el-form-item label="条件表达式">
                                    <el-input v-model="selectedNode.config.condition" type="textarea" rows="2" placeholder='{{experiment.status}} == "completed"'></el-input>
                                </el-form-item>
                                <el-form-item label="运算符">
                                    <el-select v-model="selectedNode.config.operator">
                                        <el-option label="等于 (==)" value="==" />
                                        <el-option label="不等于 (!=)" value="!=" />
                                        <el-option label="大于 (>)" value=">" />
                                        <el-option label="小于 (<)" value="<" />
                                        <el-option label="大于等于 (>=)" value=">=" />
                                        <el-option label="小于等于 (<=)" value="<=" />
                                        <el-option label="包含 (contains)" value="contains" />
                                        <el-option label="正则匹配 (regex)" value="regex" />
                                    </el-select>
                                </el-form-item>
                            </template>
                        </el-form>
                    </div>
                </div>
            </div>

            <!-- 工作流实例列表 -->
            <div v-show="activeTab === 'instances'">
                <el-row :gutter="20" style="margin-bottom: 20px;">
                    <el-col :span="8">
                        <el-select v-model="instanceFilter.workflow_id" placeholder="选择工作流" clearable @change="fetchInstances">
                            <el-option
                                v-for="wf in workflows"
                                :key="wf.id"
                                :label="wf.name"
                                :value="wf.id"
                            />
                        </el-select>
                    </el-col>
                    <el-col :span="8">
                        <el-select v-model="instanceFilter.status" placeholder="选择状态" clearable @change="fetchInstances">
                            <el-option label="运行中" value="运行中" />
                            <el-option label="已完成" value="已完成" />
                            <el-option label="失败" value="失败" />
                            <el-option label="已暂停" value="已暂停" />
                        </el-select>
                    </el-col>
                </el-row>

                <el-table :data="instances" v-loading="instancesLoading" stripe style="width: 100%">
                    <el-table-column prop="id" label="ID" width="80"></el-table-column>
                    <el-table-column prop="instance_name" label="实例名称" width="250"></el-table-column>
                    <el-table-column prop="status" label="状态" width="120">
                        <template #default="scope">
                            <span :class="'status-badge status-' + getStatusClass(scope.row.status)">
                                {{ scope.row.status }}
                            </span>
                        </template>
                    </el-table-column>
                    <el-table-column prop="trigger_type" label="触发方式" width="100"></el-table-column>
                    <el-table-column prop="created_at" label="创建时间" width="180">
                        <template #default="scope">
                            {{ formatDate(scope.row.created_at) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="duration" label="耗时(秒)" width="100"></el-table-column>
                    <el-table-column label="操作" width="350">
                        <template #default="scope">
                            <el-button size="small" @click="viewInstanceDetail(scope.row.id)">详情</el-button>
                            <el-button size="small" @click="viewInstanceLogs(scope.row.id)">日志</el-button>
                            <el-button size="small" type="warning" @click="pauseInstance(scope.row.id)" v-if="scope.row.status === '运行中'">暂停</el-button>
                            <el-button size="small" type="success" @click="resumeInstance(scope.row.id)" v-if="scope.row.status === '已暂停'">恢复</el-button>
                            <el-button size="small" type="info" @click="retryInstance(scope.row.id)" v-if="scope.row.status === '失败'">重试</el-button>
                        </template>
                    </el-table-column>
                </el-table>

                <el-pagination
                    v-model:current-page="instancePage"
                    v-model:page-size="instancePageSize"
                    :page-sizes="[10, 20, 50]"
                    :total="instanceTotal"
                    layout="total, sizes, prev, pager, next"
                    @size-change="fetchInstances"
                    @current-change="fetchInstances"
                    style="margin-top: 20px; justify-content: center"
                />
            </div>
        </div>

        <!-- 工作流详情对话框 -->
        <el-dialog v-model="workflowDetailVisible" title="工作流配置" width="50%">
            <el-form label-width="120px">
                <el-form-item label="工作流名称">
                    <el-input v-model="workflowForm.name"></el-input>
                </el-form-item>
                <el-form-item label="工作流描述">
                    <el-input v-model="workflowForm.description" type="textarea" rows="2"></el-input>
                </el-form-item>
                <el-form-item label="Cron表达式">
                    <el-input v-model="workflowForm.cron_expression" placeholder="0 2 * * * (每天凌晨2点)"></el-input>
                </el-form-item>
                <el-form-item label="启用定时调度">
                    <el-switch v-model="workflowForm.cron_enabled"></el-switch>
                </el-form-item>
            </el-form>
            <template #footer>
                <el-button @click="workflowDetailVisible = false">取消</el-button>
                <el-button type="primary" @click="confirmSaveWorkflow">确定</el-button>
            </template>
        </el-dialog>

        <!-- 实例详情对话框 -->
        <el-dialog v-model="instanceDetailVisible" title="工作流实例详情" width="70%">
            <div v-if="currentInstance">
                <el-descriptions :column="2" border>
                    <el-descriptions-item label="实例ID">{{ currentInstance.id }}</el-descriptions-item>
                    <el-descriptions-item label="实例名称">{{ currentInstance.instance_name }}</el-descriptions-item>
                    <el-descriptions-item label="状态">
                        <span :class="'status-badge status-' + getStatusClass(currentInstance.status)">
                            {{ currentInstance.status }}
                        </span>
                    </el-descriptions-item>
                    <el-descriptions-item label="触发方式">{{ currentInstance.trigger_type }}</el-descriptions-item>
                    <el-descriptions-item label="创建时间">{{ formatDate(currentInstance.created_at) }}</el-descriptions-item>
                    <el-descriptions-item label="开始时间">{{ formatDate(currentInstance.started_at) }}</el-descriptions-item>
                    <el-descriptions-item label="结束时间">{{ formatDate(currentInstance.finished_at) }}</el-descriptions-item>
                    <el-descriptions-item label="耗时">{{ currentInstance.duration }} 秒</el-descriptions-item>
                </el-descriptions>

                <el-divider>节点执行情况</el-divider>
                <el-timeline>
                    <el-timeline-item
                        v-for="node in currentInstance.nodes_execution"
                        :key="node.node_id"
                        :timestamp="formatDate(node.started_at)"
                        :type="getNodeStatusType(node.status)"
                    >
                        <h4>{{ node.node_name }} ({{ node.node_type }})</h4>
                        <p>状态: {{ node.status }}</p>
                        <p v-if="node.finished_at">完成时间: {{ formatDate(node.finished_at) }}</p>
                        <p v-if="node.error_message" style="color: red;">错误: {{ node.error_message }}</p>
                        <el-collapse v-if="node.output_data">
                            <el-collapse-item title="输出数据" name="1">
                                <pre>{{ JSON.stringify(node.output_data, null, 2) }}</pre>
                            </el-collapse-item>
                        </el-collapse>
                    </el-timeline-item>
                </el-timeline>
            </div>
        </el-dialog>

        <!-- 实例日志对话框 -->
        <el-dialog v-model="instanceLogsVisible" title="工作流实例日志" width="70%">
            <el-table :data="instanceLogs" stripe style="width: 100%" max-height="500">
                <el-table-column prop="log_time" label="时间" width="180">
                    <template #default="scope">
                        {{ formatDate(scope.row.log_time) }}
                    </template>
                </el-table-column>
                <el-table-column prop="log_level" label="级别" width="80">
                    <template #default="scope">
                        <el-tag :type="scope.row.log_level === 'ERROR' ? 'danger' : 'info'" size="small">
                            {{ scope.row.log_level }}
                        </el-tag>
                    </template>
                </el-table-column>
                <el-table-column prop="node_id" label="节点ID" width="120"></el-table-column>
                <el-table-column prop="log_message" label="日志内容"></el-table-column>
            </el-table>
        </el-dialog>
    </div>

    <script>
        const { createApp } = Vue;
        const { ElMessage, ElMessageBox } = ElementPlus;

        const API_BASE = 'http://localhost:8000';

        createApp({
            data() {
                return {
                    activeTab: 'list',

                    // 工作流列表
                    workflows: [],
                    loading: false,
                    currentPage: 1,
                    pageSize: 20,
                    total: 0,
                    searchName: '',

                    // 工作流编辑器
                    nodeTypes: [
                        { type: 'create_experiment', name: '创建实验', description: '基于模板创建实验', icon: 'el-icon-document-add' },
                        { type: 'download_data', name: '下载数据', description: '从数据源下载数据', icon: 'el-icon-download' },
                        { type: 'data_processing', name: '数据处理', description: '调用API处理数据', icon: 'el-icon-setting' },
                        { type: 'condition', name: '条件判断', description: '根据条件分支', icon: 'el-icon-fork' }
                    ],
                    editorNodes: [],
                    connections: [],
                    selectedNode: null,
                    nextNodeId: 1,
                    draggingNode: null,
                    dragOffset: { x: 0, y: 0 },
                    connectingFrom: null,
                    canvasSize: { width: 2000, height: 2000 },
                    experimentTemplates: [],

                    // 工作流表单
                    workflowForm: {
                        name: '',
                        description: '',
                        cron_expression: '',
                        cron_enabled: false
                    },
                    workflowDetailVisible: false,
                    currentWorkflowId: null,

                    // 工作流实例
                    instances: [],
                    instancesLoading: false,
                    instancePage: 1,
                    instancePageSize: 20,
                    instanceTotal: 0,
                    instanceFilter: {
                        workflow_id: null,
                        status: null
                    },
                    currentInstance: null,
                    instanceDetailVisible: false,
                    instanceLogsVisible: false,
                    instanceLogs: []
                };
            },
            mounted() {
                this.fetchWorkflows();
                this.fetchExperimentTemplates();
                this.fetchInstances();

                // 添加鼠标移动和释放事件监听
                document.addEventListener('mousemove', this.onMouseMove);
                document.addEventListener('mouseup', this.onMouseUp);
            },
            beforeUnmount() {
                document.removeEventListener('mousemove', this.onMouseMove);
                document.removeEventListener('mouseup', this.onMouseUp);
            },
            methods: {
                // ========== 工作流列表相关 ==========
                async fetchWorkflows() {
                    this.loading = true;
                    try {
                        const response = await axios.get(`${API_BASE}/api/workflows`, {
                            params: {
                                page: this.currentPage,
                                page_size: this.pageSize,
                                name: this.searchName || undefined
                            }
                        });
                        this.workflows = response.data.items;
                        this.total = response.data.total;
                    } catch (error) {
                        ElMessage.error('获取工作流列表失败: ' + (error.response?.data?.detail || error.message));
                    } finally {
                        this.loading = false;
                    }
                },

                createNewWorkflow() {
                    this.currentWorkflowId = null;
                    this.editorNodes = [];
                    this.connections = [];
                    this.selectedNode = null;
                    this.nextNodeId = 1;
                    this.workflowForm = {
                        name: '',
                        description: '',
                        cron_expression: '',
                        cron_enabled: false
                    };
                    this.activeTab = 'editor';
                },

                async editWorkflow(workflow) {
                    try {
                        const response = await axios.get(`${API_BASE}/api/workflows/${workflow.id}`);
                        const wf = response.data;

                        this.currentWorkflowId = wf.id;
                        this.workflowForm = {
                            name: wf.name,
                            description: wf.description,
                            cron_expression: wf.cron_expression || '',
                            cron_enabled: wf.cron_enabled
                        };

                        // 加载工作流定义到编辑器
                        const definition = wf.workflow_definition;
                        this.editorNodes = definition.nodes.map((node, index) => ({
                            ...node,
                            x: 100 + (index % 3) * 250,
                            y: 100 + Math.floor(index / 3) * 150,
                            config: node.config || {}
                        }));

                        this.nextNodeId = this.editorNodes.length + 1;
                        this.updateConnections();
                        this.activeTab = 'editor';
                    } catch (error) {
                        ElMessage.error('加载工作流失败: ' + (error.response?.data?.detail || error.message));
                    }
                },

                async deleteWorkflow(id) {
                    try {
                        await ElMessageBox.confirm('确定要删除这个工作流吗？', '警告', {
                            confirmButtonText: '确定',
                            cancelButtonText: '取消',
                            type: 'warning'
                        });

                        await axios.delete(`${API_BASE}/api/workflows/${id}`);
                        ElMessage.success('工作流已删除');
                        this.fetchWorkflows();
                    } catch (error) {
                        if (error !== 'cancel') {
                            ElMessage.error('删除失败: ' + (error.response?.data?.detail || error.message));
                        }
                    }
                },

                async runWorkflow(id) {
                    try {
                        const response = await axios.post(`${API_BASE}/api/workflows/${id}/run`, {
                            input_params: {}
                        });
                        ElMessage.success(`工作流已启动, 实例ID: ${response.data.instance_id}`);
                        this.activeTab = 'instances';
                        this.fetchInstances();
                    } catch (error) {
                        ElMessage.error('启动失败: ' + (error.response?.data?.detail || error.message));
                    }
                },

                // ========== 工作流编辑器相关 ==========
                async fetchExperimentTemplates() {
                    try {
                        const response = await axios.get(`${API_BASE}/api/experiment-templates`, {
                            params: { page: 1, page_size: 100 }
                        });
                        this.experimentTemplates = response.data.items;
                    } catch (error) {
                        console.error('获取实验模板失败:', error);
                    }
                },

                addNode(nodeType) {
                    const node = {
                        id: `node${this.nextNodeId++}`,
                        type: nodeType.type,
                        name: nodeType.name,
                        x: 50 + this.editorNodes.length * 50,
                        y: 50 + this.editorNodes.length * 50,
                        next: null,
                        config: this.getDefaultConfig(nodeType.type)
                    };
                    this.editorNodes.push(node);
                },

                getDefaultConfig(type) {
                    const configs = {
                        create_experiment: { template_id: null, experiment_name: '', poll_interval: '30min' },
                        download_data: { source_type: 'OBS', source_path: '', target_path: '', download_strategy: 'overwrite' },
                        data_processing: { api_function: '', request_params: '' },
                        condition: { condition: '', operator: '==' }
                    };
                    return configs[type] || {};
                },

                selectNode(node) {
                    this.selectedNode = node;
                },

                deselectNode() {
                    this.selectedNode = null;
                },

                removeNode(nodeId) {
                    this.editorNodes = this.editorNodes.filter(n => n.id !== nodeId);
                    // 移除相关连接
                    this.editorNodes.forEach(n => {
                        if (n.next === nodeId) {
                            n.next = null;
                        }
                    });
                    this.updateConnections();
                    if (this.selectedNode && this.selectedNode.id === nodeId) {
                        this.selectedNode = null;
                    }
                },

                startDrag(event, node) {
                    this.draggingNode = node;
                    const rect = event.target.getBoundingClientRect();
                    this.dragOffset = {
                        x: event.clientX - rect.left,
                        y: event.clientY - rect.top
                    };
                },

                onMouseMove(event) {
                    if (this.draggingNode) {
                        const canvas = this.$refs.canvas;
                        const canvasRect = canvas.getBoundingClientRect();
                        this.draggingNode.x = event.clientX - canvasRect.left - this.dragOffset.x + canvas.scrollLeft;
                        this.draggingNode.y = event.clientY - canvasRect.top - this.dragOffset.y + canvas.scrollTop;
                        this.updateConnections();
                    }
                },

                onMouseUp() {
                    this.draggingNode = null;
                },

                connectOutput(node) {
                    if (this.connectingFrom === null) {
                        this.connectingFrom = node;
                        ElMessage.info('请选择目标节点的输入点');
                    }
                },

                connectInput(node) {
                    if (this.connectingFrom && this.connectingFrom.id !== node.id) {
                        this.connectingFrom.next = node.id;
                        this.updateConnections();
                        ElMessage.success('连接成功');
                        this.connectingFrom = null;
                    } else if (this.connectingFrom) {
                        ElMessage.warning('不能连接到自己');
                        this.connectingFrom = null;
                    }
                },

                updateConnections() {
                    this.connections = [];
                    this.editorNodes.forEach(node => {
                        if (node.next) {
                            const nextNode = this.editorNodes.find(n => n.id === node.next);
                            if (nextNode) {
                                this.connections.push({
                                    x1: node.x + 150,
                                    y1: node.y + 40,
                                    x2: nextNode.x,
                                    y2: nextNode.y + 40
                                });
                            }
                        }
                    });
                },

                clearCanvas() {
                    ElMessageBox.confirm('确定要清空画布吗？', '警告', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        type: 'warning'
                    }).then(() => {
                        this.editorNodes = [];
                        this.connections = [];
                        this.selectedNode = null;
                        this.nextNodeId = 1;
                    }).catch(() => {});
                },

                saveWorkflow() {
                    if (this.editorNodes.length === 0) {
                        ElMessage.warning('请至少添加一个节点');
                        return;
                    }
                    this.workflowDetailVisible = true;
                },

                async confirmSaveWorkflow() {
                    if (!this.workflowForm.name) {
                        ElMessage.warning('请填写工作流名称');
                        return;
                    }

                    const workflow_definition = {
                        nodes: this.editorNodes.map(n => ({
                            id: n.id,
                            type: n.type,
                            name: n.name,
                            config: n.config,
                            next: n.next
                        }))
                    };

                    try {
                        if (this.currentWorkflowId) {
                            // 更新工作流
                            await axios.put(`${API_BASE}/api/workflows/${this.currentWorkflowId}`, {
                                name: this.workflowForm.name,
                                description: this.workflowForm.description,
                                workflow_definition: workflow_definition,
                                cron_expression: this.workflowForm.cron_expression || null,
                                cron_enabled: this.workflowForm.cron_enabled
                            });
                            ElMessage.success('工作流已更新');
                        } else {
                            // 创建工作流
                            await axios.post(`${API_BASE}/api/workflows`, {
                                name: this.workflowForm.name,
                                description: this.workflowForm.description,
                                workflow_definition: workflow_definition,
                                cron_expression: this.workflowForm.cron_expression || null,
                                cron_enabled: this.workflowForm.cron_enabled,
                                created_by: 'web_user'
                            });
                            ElMessage.success('工作流已创建');
                        }
                        this.workflowDetailVisible = false;
                        this.fetchWorkflows();
                        this.activeTab = 'list';
                    } catch (error) {
                        ElMessage.error('保存失败: ' + (error.response?.data?.detail || error.message));
                    }
                },

                // ========== 工作流实例相关 ==========
                async fetchInstances() {
                    this.instancesLoading = true;
                    try {
                        const response = await axios.get(`${API_BASE}/api/workflows/instances/list`, {
                            params: {
                                page: this.instancePage,
                                page_size: this.instancePageSize,
                                workflow_id: this.instanceFilter.workflow_id || undefined,
                                status: this.instanceFilter.status || undefined
                            }
                        });
                        this.instances = response.data.items;
                        this.instanceTotal = response.data.total;
                    } catch (error) {
                        ElMessage.error('获取实例列表失败: ' + (error.response?.data?.detail || error.message));
                    } finally {
                        this.instancesLoading = false;
                    }
                },

                async viewInstanceDetail(id) {
                    try {
                        const response = await axios.get(`${API_BASE}/api/workflows/instances/${id}`);
                        this.currentInstance = response.data;
                        this.instanceDetailVisible = true;
                    } catch (error) {
                        ElMessage.error('获取实例详情失败: ' + (error.response?.data?.detail || error.message));
                    }
                },

                async viewInstanceLogs(id) {
                    try {
                        const response = await axios.get(`${API_BASE}/api/workflows/instances/${id}/logs`);
                        this.instanceLogs = response.data.logs;
                        this.instanceLogsVisible = true;
                    } catch (error) {
                        ElMessage.error('获取日志失败: ' + (error.response?.data?.detail || error.message));
                    }
                },

                async pauseInstance(id) {
                    try {
                        await axios.post(`${API_BASE}/api/workflows/instances/${id}/pause`);
                        ElMessage.success('暂停请求已发送');
                        this.fetchInstances();
                    } catch (error) {
                        ElMessage.error('暂停失败: ' + (error.response?.data?.detail || error.message));
                    }
                },

                async resumeInstance(id) {
                    try {
                        await axios.post(`${API_BASE}/api/workflows/instances/${id}/resume`);
                        ElMessage.success('工作流已恢复');
                        this.fetchInstances();
                    } catch (error) {
                        ElMessage.error('恢复失败: ' + (error.response?.data?.detail || error.message));
                    }
                },

                async retryInstance(id) {
                    try {
                        await axios.post(`${API_BASE}/api/workflows/instances/${id}/retry`, {});
                        ElMessage.success('重试已开始');
                        this.fetchInstances();
                    } catch (error) {
                        ElMessage.error('重试失败: ' + (error.response?.data?.detail || error.message));
                    }
                },

                // ========== 工具方法 ==========
                formatDate(dateString) {
                    if (!dateString) return '-';
                    const date = new Date(dateString);
                    return date.toLocaleString('zh-CN');
                },

                getStatusClass(status) {
                    const map = {
                        '运行中': 'running',
                        '已完成': 'completed',
                        '失败': 'failed',
                        '已暂停': 'paused',
                        '暂停中': 'paused',
                        '等待中': 'running',
                        '初始化': 'running'
                    };
                    return map[status] || 'running';
                },

                getNodeStatusType(status) {
                    const map = {
                        '已完成': 'success',
                        '失败': 'danger',
                        '运行中': 'primary',
                        '待执行': 'info'
                    };
                    return map[status] || 'info';
                }
            }
        }).use(ElementPlus).mount('#app');
    </script>
</body>
</html>
